<h2>Global lighting</h2>

<p>Lighting module is one of the most convoluted parts of <strong>rot.js</strong>: it is a mix of various concepts introduced in simpler components. <code>ROT.Lighting</code> is used to compute how multiple light sources mix and reflect in a cellular map (using a highly simplified radiosity-like algorithm).</p>

<p>To compute a lighting, you need the following:</p>
<ul>
	<li>a <code>ROT.FOV</code> instance, which is used to compute the areas lit by light sources;</li>
	<li>a <code>lightingCallback</code> which notifies you about the resulting light for a given coordinates;</li>
	<li>a set of lights, defined by their position (x, y) and color.</li>
</ul>

<p>If you decide to use a <em>two-pass</em> lighting (more light, more realistic light spread, more computation time), you also need:</p>
<ul>
	<li>a <code>reflectivityCallback</code> which is used to return how much individual map cells reflect incoming light. Please note that wall cells should not reflect any light for the purpose of lighting computation.</li>
</ul>

<p>Finally, the <code>ROT.Lighting</code> function accepts an optional configuration object as its second argument. This object may contain:</p>
<ul>
	<li><code>range</code> &ndash; maximum range for the most powerful light source</li>
	<li><code>passes</code> &ndash; number of computation passes (1: no reflectivity used, 2: reflectivity used)</li>
	<li><code>emissionThreshold</code> &ndash; minimal amount of light at a cell to be re-emited (only for passes>1)</li>
</ul>

<div class="example">
ROT.RNG.setSeed(12345);

var mapData = {};
var lightData = {};
var W = 60;
var H = 40;

/* build a map */
var map = new ROT.Map.Cellular(W, H).randomize(0.5);
function createCallback(x, y, value) {
	mapData[x+","+y] = value;
}
for (var i=0; i&lt;4; i++) { 
	map.create(createCallback);
}

/* prepare a FOV algorithm */
function lightPasses(x, y) { 
	return (mapData[x+","+y] == 1);
}
var fov = new ROT.FOV.PreciseShadowcasting(lightPasses, {topology:4});

/* prepare a lighting algorithm */
function reflectivity(x, y) {
	return (mapData[x+","+y] == 1 ? 0.3 : 0);
}
var lighting = new ROT.Lighting(reflectivity, {range:12, passes:2});
lighting.setFOV(fov);
lighting.setLight(12, 12, [240, 240, 30]);
lighting.setLight(20, 20, [240, 60, 60]);
lighting.setLight(45, 25, [200, 200, 200]);

function lightingCallback(x, y, color) {
	lightData[x+","+y] = color;
}
lighting.compute(lightingCallback);

/* draw the resulting mix of mapData and lightData */
var display = new ROT.Display({fontSize:8, width:W, height:H});
SHOW(display.getContainer());

/* all cells are lit by ambient light; some are also lit by light sources */
var ambientLight = [100, 100, 100];
for (var id in mapData) {
	var parts = id.split(",");
	var x = parseInt(parts[0]);
	var y = parseInt(parts[1]);

	var baseColor = (mapData[id] ? [100, 100, 100] : [50, 50, 50]);
	var light = ambientLight;

	if (id in lightData) { /* add light from our computation */
		light = ROT.Color.add(light, lightData[id]);
	}

	var finalColor = ROT.Color.multiply(baseColor, light);
	display.draw(x, y, null, null, ROT.Color.toRGB(finalColor));
}
</div>
